home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
551-575
/
disk_553
/
24bittools
/
iff24to8
/
write.c
< prev
Wrap
C/C++ Source or Header
|
1992-05-06
|
8KB
|
323 lines
#include "iff.h"
/* WriteILBM.c: Generates 2-24 bit IFF files
(c) 1991 Dallas J. Hodgson */
SafeWrite(BPTR fp,void *buf,int length)
{
return((Write(fp,buf,length)==-1) ? TRUE:FALSE);
}
WriteILBM(char *fspec,struct PicMap *picmap)
{
BPTR fp=NULL;
BitMapHeader bmhd;
Chunk header;
long id;
int marker,bodylen,eof,err=TRUE;
short numCols=1<<picmap->BitMap.Depth;
if (!(fp=Open(fspec,MODE_NEWFILE))) goto cleanup;
header.ckID=ID_FORM;
header.ckSize=0; /* GETS CORRECTED LATER */
if (SafeWrite(fp,&header,sizeof(header))) goto cleanup;
id=ID_ILBM;
if (SafeWrite(fp,&id,sizeof(id))) goto cleanup;
header.ckID=ID_BMHD;
header.ckSize=sizeof(BitMapHeader);
if (SafeWrite(fp,&header,sizeof(header))) goto cleanup;
bmhd.w=picmap->BitMap.BytesPerRow*8;
bmhd.h=picmap->BitMap.Rows;
bmhd.x=bmhd.y=0;
bmhd.nPlanes=picmap->BitMap.Depth;
bmhd.masking=mskNone;
bmhd.compression=cmpByteRun1;
bmhd.pad1=0;
bmhd.transparentColor=0;
bmhd.xAspect=1;
bmhd.yAspect=1;
bmhd.pageWidth=bmhd.w;
bmhd.pageHeight=bmhd.h;
if (SafeWrite(fp,&bmhd,sizeof(bmhd))) goto cleanup;
if (picmap->BitMap.Depth<=8) {
header.ckID=ID_CMAP;
header.ckSize=numCols*3;
if (SafeWrite(fp,&header,sizeof(header))) goto cleanup;
if (SafeWrite(fp,&picmap->palette,numCols*3))
goto cleanup;
if (SafePad(fp,header.ckSize)) goto cleanup;
}
header.ckID=ID_CAMG;
header.ckSize=sizeof(picmap->ViewModes);
if (SafeWrite(fp,&header,sizeof(header))) goto cleanup;
if (SafeWrite(fp,&picmap->ViewModes,sizeof(picmap->ViewModes))) goto cleanup;
header.ckID=ID_BODY;
header.ckSize=0; /* GETS CORRECTED LATER */
if ((marker=Seek(fp,0,OFFSET_CURRENT))==-1) goto cleanup;
if (SafeWrite(fp,&header,sizeof(header))) goto cleanup;
if (!(bodylen=WriteBody(fp,picmap))) goto cleanup;
if (SafePad(fp,bodylen)) goto cleanup;
if ((eof=Seek(fp,0,OFFSET_CURRENT))==-1) goto cleanup;
/* Go back and fix the two size values */
if (Seek(fp,marker,OFFSET_BEGINNING)==-1) goto cleanup;
header.ckID=ID_BODY;
header.ckSize=bodylen;
if (SafeWrite(fp,&header,sizeof(header))) goto cleanup;
if (Seek(fp,0,OFFSET_BEGINNING)==-1) goto cleanup;
header.ckID=ID_FORM;
header.ckSize=eof-sizeof(header);
if (SafeWrite(fp,&header,sizeof(header))) goto cleanup;
err=FALSE;
cleanup:
if (fp) Close(fp);
return(err);
}
#define WRITE_SIZE 8192
#define MAX_COMPRESSED_LINE 2048
WriteBody(BPTR fp,struct PicMap *picmap)
{
unsigned char *rawbuf,*dstPtr,*packbuf=NULL;
short line,plane,count,bytelen;
short w=picmap->BitMap.BytesPerRow*8,h=picmap->BitMap.Rows;
int total=0,len=0;
if (!(packbuf=AllocMem(WRITE_SIZE+MAX_COMPRESSED_LINE,MEMF_PUBLIC))) {
#ifdef DEBUG
printf("WriteBody: couldn't allocate packbuf\n");
#endif
goto cleanup;
}
/* roundup width to a multiple of 16 pixels, if necessary; important
for deinterleaving brushes correctly! */
if (w%16) w=(((w/16)+1)*16);
bytelen=w/8;
/* Read each line from display, 1 plane at a time. Optionally compress
each bitplane separately, and write each bitplane out. */
dstPtr=packbuf;
for (line=0;line<h;line++) {
for (plane=0;plane<picmap->BitMap.Depth;plane++) {
rawbuf=picmap->BitMap.Planes[plane]+(picmap->BitMap.BytesPerRow*line);
/* A worst-case compression would result in the output being TWICE
the size of the input data. If the compressed version is larger
than the original, then write the uncompressed version.
*/
if ((count=PackBits2((char *)rawbuf,(char *)dstPtr,bytelen))<=bytelen) {
dstPtr+=count;
len+=count;
total+=count;
}
else {
count=PackUncompressedBits(rawbuf,dstPtr,bytelen);
dstPtr+=count;
len+=count;
total+=count;
}
if (len >= WRITE_SIZE) {
if (SafeWrite(fp,packbuf,len)) {
total=0;
goto cleanup;
}
len=0;
dstPtr=packbuf;
}
}
}
/* Flush out anything left in the output buffer after the last pass */
if (len)
if (SafeWrite(fp,packbuf,len)) total=0;
cleanup:
if (packbuf) FreeMem(packbuf,WRITE_SIZE+MAX_COMPRESSED_LINE);
return(total);
}
SafePad(BPTR fp,int len)
{
static char pad=0;
if (len & 1)
if (SafeWrite(fp,&pad,1)) return(TRUE);
return(FALSE);
}
/*
* PRIVATE: PackUncompressedBits is an uncompressed stream writer, suitable
* for those occasions when RLE encoding just doesn't do the job.
*/
int
PackUncompressedBits(unsigned char *src,unsigned char *dst,int size)
{
unsigned char *orig=dst;
int len;
while(size) {
if (size<128) len=size; else len=127;
*dst++ = len-1;
CopyMem((char *)src,(char *)dst,len);
src+=len;
dst+=len;
size-=len;
}
return(dst-orig);
}
#define MAXRUN 127
/*
* PRIVATE: PackBits2 is derived from the original Macintosh compress
* routine, but modified so the maximum compressed run is 127 instead
* of 128 bytes. According to the IFF docs, a compressed run of 128 is
* illegal, tho' possible if your unpacker routine uses unsigned int
* (instead of signed char) comparisons for the expansion.
*
* Runs longer than 127 bytes are permissible, but will be broken up
* into smaller runs of 127 bytes or less.
*/
int
PackBits2(char *src,char *dst,int size)
{
char c;
char *sp, *dp, *start;
int runChar;
int runCount,nonRunCount;
/*
* Initialize.
*/
sp = src;
dp = dst;
start = sp;
runChar = *sp++;
--size;
runCount = 1;
/*
* Loop over all input bytes.
*/
while (size > 0) {
c = *sp++;
--size;
if (c == runChar) {
++runCount;
}
else {
/*
* This is the end of a run of bytes (possibly a very short run).
* Figure out what to do with it.
*/
if (runCount >= 3) {
/*
* If the run length is greater than three, compress it. Runs
* of smaller than three are treated as non-runs.
*/
nonRunCount = (sp - 1) - start - runCount;
/*
* First, output any accumulated non-run bytes.
*/
if (nonRunCount > 0) {
*dp++ = nonRunCount - 1;
while (nonRunCount--) {
*dp++ = *start++;
}
}
/*
* Now output the compressed run. Since the max run length we
* can encode is MAXRUN, longer runs must be segmented.
*/
while (runCount > MAXRUN) {
/*
* Loop to output segments of runs longer that MAXRUN.
*/
*dp++ = -(MAXRUN - 1);
*dp++ = runChar;
runCount -= MAXRUN;
}
/*
* Output the last (or only) run of length MAXRUN or less.
*/
*dp++ = -(runCount - 1);
*dp++ = runChar;
start = sp - 1;
}
/*
* Get ready for the next time through this loop.
*/
runChar = c;
runCount = 1;
}
}
/*
* We've reached the end of the source data. Now we have to flush
* out data we haven't dealt with yet. This code is almost identical
* to the code inside the main loop, above.
*/
nonRunCount = sp - start;
if (runCount >= 3) nonRunCount -= runCount;
else runCount = 0;
/*
* Output non-run data.
*/
if (nonRunCount) {
*dp++ = nonRunCount - 1;
while (nonRunCount--) {
*dp++ = *start++;
}
}
/*
* Output compressed run.
*/
if (runCount) {
while (runCount > MAXRUN) {
*dp++ = -(MAXRUN - 1);
*dp++ = runChar;
runCount -= MAXRUN;
}
*dp++ = -(runCount - 1);
*dp++ = runChar;
}
/*
* Clean up and return.
*/
return(dp-dst);
}